package com.ibeeking.found.uaa.s.controller.v1;

import com.ibeeking.found.auth.api.common.param.RefreshTokenParam;
import com.ibeeking.found.auth.api.feign.ShopLoginClient;
import com.ibeeking.found.common.config.secret.RsaConfig;
import com.ibeeking.found.common.constants.HeaderNounConstant;
import com.ibeeking.gmc.global.api.common.dto.OauthClientDTO;
import com.ibeeking.gmc.global.api.feign.GlobalOpenFeignClient;
import com.ibeeking.found.uaa.s.constant.RedisKeyConstant;
import com.ibeeking.nematos.constants.enums.OperateLogTypeEnum;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.annotation.Log;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.encryption.EncryptUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.*;

/**
 * @ClassName UserController控制器
 * @Description 全局用户管理
 * @Author ibeeking
 * @Date 2020-12-02 15:29
 **/
@RestController
@RequestMapping("/uaa/v1")
public class ShopUaaController {

    private static final String GRANT_TYPE = "refresh_token";

    @Resource
    private RsaConfig rsaConfig;
    @Resource
    private AuthorizationServerTokenServices authorizationServerTokenServices;
    @Resource
    private GlobalOpenFeignClient globalOpenFeignClient;
    @Resource
    private ShopLoginClient shopLoginClient;
    @Resource
    private RedisUtils redisUtils;

    @Log(logType = OperateLogTypeEnum.QUERY, describe = "公钥查询")
    @GetMapping(value = "/oauth/publicKey")
    public ResponseResult<String> publicKey() {
        LogUtils.info("+++++++++++stat /oauth/publicKey ++++++++++++++++++");
        KeyPair keyPair= rsaConfig.getKeyPair();
        PublicKey keyPairPublicKey = keyPair.getPublic();
        String publicKey = EncryptUtils.RsaEncrypt.getPublicKey(keyPairPublicKey);
        LogUtils.info("+++++++++++publicKey:{} ++++++++++++++++++",publicKey);
        return ResponseResult.success(publicKey);
    }

    @Log(logType = OperateLogTypeEnum.QUERY, describe = "加载选择商户")
    @GetMapping(value = "/loadShopId")
    public ResponseResult<Boolean> loadShopId(HttpServletRequest request) {
        //校验当前用户是否有要加载的商户权限
        String userId = request.getHeader(HeaderNounConstant.USER_ID);
        String tenantId = request.getHeader(HeaderNounConstant.TENANT_ID);
        String shopId = request.getHeader(HeaderNounConstant.SHOP_ID);
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(tenantId) || StringUtils.isBlank(shopId)) {
            throw new BusinessException("请登录后再进行切换商户");
        }
        //查询当前商户的授权
        ResponseResult<List<Long>> responseResult = shopLoginClient.queryHaveShopId();
        if (null == responseResult || !responseResult.getData().contains(Long.valueOf(shopId))) {
            throw new BusinessException("未被当前商户授权");
        }
        return ResponseResult.success(true);
    }

    /**
     * 刷新token
     *
     * @param refreshTokenParam
     * @return
     */
    @PostMapping(value = "/oauth/refreshToken")
    public ResponseResult<String> refreshToken(@RequestBody RefreshTokenParam refreshTokenParam) {
        Object o = redisUtils.get(RedisKeyConstant.MODULE + RedisKeyConstant.REFRESH_TOKEN + refreshTokenParam.getJti());
        if (null == o) {
            return ResponseResult.fail("从redis获取refreshToken失败");
        }
        ResponseResult<OauthClientDTO> responseResult = globalOpenFeignClient.queryByClientId(refreshTokenParam.getClientId());
        if (null == responseResult.getData()) {
            return ResponseResult.fail(responseResult.getMsg());
        }
        OauthClientDTO oauthClientDTO = responseResult.getData();
        Map<String, String> requestParameters = new HashMap<>(4);
        requestParameters.put("grant_type", GRANT_TYPE);
        requestParameters.put("client_id", refreshTokenParam.getClientId());
        requestParameters.put("client_secret", EncryptUtils.RsaEncrypt.encrypt(oauthClientDTO.getClientSecret(), rsaConfig.getKeyPair().getPublic()));
        requestParameters.put(GRANT_TYPE, o.toString());
        Set<String> scopes = new HashSet<>();
        scopes.addAll(Arrays.asList(oauthClientDTO.getScope().split(",")));
        TokenRequest tokenRequest = new TokenRequest(requestParameters, refreshTokenParam.getClientId(), scopes, GRANT_TYPE);
        OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.refreshAccessToken(o.toString(), tokenRequest);
        int expiresIn = oAuth2AccessToken.getExpiresIn();
        String refreshToken = oAuth2AccessToken.getRefreshToken().getValue();
        String jti = oAuth2AccessToken.getAdditionalInformation().get(HeaderNounConstant.JWT_JTI).toString().replaceAll("-", "");
        redisUtils.set(RedisKeyConstant.MODULE + RedisKeyConstant.REFRESH_TOKEN + jti, refreshToken, expiresIn - 5);
        return ResponseResult.success(oAuth2AccessToken.getTokenType() + " " + oAuth2AccessToken.getValue());
    }
}
